直击答案
答案:会。
这是因为浏览器需要严格遵循“只有在 defer 文件都下载、执行完毕之后才能触发 DOMContentLoaded 事件”这一明确的执行顺序,所以当有多个 defer 脚本需要下载与执行时,如果其中一个或多个脚本下载缓慢或执行耗时的话,那就会直接阻塞和延迟 DOMContentLoaded 事件的触发(下图清晰的展示了其中的依赖关系)。

答疑解惑
defer 脚本与 DOMContentLoaded
1.defer 脚本的执行是同步的
虽然 defer 脚本的下载是异步的(不阻塞 HTML 解析),但它们的执行是严格按照顺序、同步进行的。浏览器会等待第一个 defer 脚本下载并执行完毕,再开始执行下一个,以此类推。任何一个脚本执行过慢,都会阻塞后续脚本的执行。
2.DOMContentLoaded 必须等待
DOMContentLoaded 事件的设计本意就是:“当初始 HTML 文档被完全加载和解析,并且所有延迟脚本(defer)都执行完毕时”才触发。因此,事件触发前的那一刻,浏览器必须确保所有 defer 脚本都已完成执行。这是 Web 标准规定的行为。
当 DOMContentLoaded 事件被延迟触发,会带来什么影响?
当 DOMContentLoaded 事件被延迟触发,首当其冲的影响就是用户体验问题:用户会感觉页面“卡住了”。虽然此时页面已经可以被看到,但是任何依赖于 DOMContentLoaded 事件来初始化的交互功能都无法工作,因为交互功能的初始化脚本还在排队等待执行。
其次受到影响的就是让程序员头秃的性能指标:Web 性能关键指标 DOMContentLoaded 时间 (DCL) 会变得非常差,这会直接影响 Lighthouse 等性能测评工具的分数。
解决方案(既然影响这么大,就让程序员加班解决吧)
1.保持 defer 脚本轻量
完美的 defer 脚本应该只包含组件定义、注册和关键的初始化前置逻辑,应避免执行重量级的同步计算、同步网络请求等操作;
2.代码拆分与合并
可以将多个小文件合并成一个,以减少 HTTP 请求数量和脚本执行调度;
但如果有一个非常大的、非关键的脚本,可以在分析后将重要逻辑拆解出来独立成一个文件,另将不紧急或耗时的逻辑放到 DOMContentLoaded 事件之后执行;
写在最后
综上,defer 脚本在下载阶段是性能助手,但在执行阶段却可能成为瓶颈。所以作为前端工程师的我们必须履行“契约”:保证它轻装上阵,这样才不辜负它为我们提供了一个可靠的、可预测的执行顺序(在 DOM 构建后,在 DCL 前)。
P.S. defer 是一个为外部脚本设计的性能优化属性,所以当在页面內联的 script 标签中设置 defer 时是没有效果的。










